package com.xiyuan.smartutils.client.ws.core.auth;

import com.xiyuan.smartutils.client.http.HttpHeader;
import com.xiyuan.smartutils.client.ws.WebSocket;
import com.xiyuan.smartutils.client.exception.WebSocketException;
import com.xiyuan.smartutils.client.ws.util.StringUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * The Class AbstractAuthenticator.
 *
 * @author xiyuan-lgz
 */
abstract public class AbstractAuthenticator implements Authenticator {
    
    /** The websocket. */
    protected WebSocket websocket;
    
    /** The credentials. */
    protected Credentials credentials;

    private boolean isDone = false;

    /**
     * Instantiates a new abstract authenticator.
     */
    public AbstractAuthenticator(){
    }
    
    /* (non-Javadoc)
     * @see jp.a840.websocket.auth.Authenticator#getCredentials(java.lang.String, java.lang.String, jp.a840.websocket.HttpHeader, java.lang.String)
     */
    public String getCredentials(String method, String requestUri, HttpHeader header, String authenticateHeaderName) throws WebSocketException {
        if(isDone) {
            throw new IllegalStateException("this Authenticator already executed");
        }

        List<String> proxyAuthenticateList = header
                .getHeaders(authenticateHeaderName);
        
        List<Challenge> challengeList = new ArrayList<Challenge>();
        for (String proxyAuthenticateStr : proxyAuthenticateList) {
            // key:   Proxy-Authenticate
            // value: Basic realm="WallyWorld"
            String[] parts = proxyAuthenticateStr.split(" +", 2);
            AuthScheme authScheme = null;
            try{
                authScheme = AuthScheme.valueOf(parts[0]);
            }catch(IllegalArgumentException e){
                continue; // Skip non-supported Scheme
            }

            String param = null;
            if(parts.length > 1){
                param = parts[1];
            }

            challengeList.add(new Challenge(method, requestUri, authScheme, param));
        }
        
        return getCredentials(challengeList);
    }

    /* (non-Javadoc)
     * @see jp.a840.websocket.proxy.ProxyCredentials#getCredentials()
     */
    /**
     * Gets the credentials.
     *
     * @param challengeList the challenge list
     * @return the credentials
     * @throws WebSocketException the web socket exception
     */
    abstract public String getCredentials(List<Challenge> challengeList) throws WebSocketException;
    
    /* (non-Javadoc)
     * @see jp.a840.websocket.auth.Authenticator#init(jp.a840.websocket.WebSocket, jp.a840.websocket.auth.Credentials)
     */
    public void init(WebSocket websocket, Credentials credentials) {
        if(isDone) {
            throw new IllegalStateException("this Authenticator already executed");
        }
        this.websocket = websocket;
        this.credentials = credentials;
    }

    protected void parseParams(Map<String, String> paramMap, String authParams){
        paramMap.putAll(StringUtil.parseKeyValues(authParams, ','));
    }

    public void done() {
        isDone = true;
    }

    public boolean isDone() {
        return isDone;
    }

    public boolean isNeedAuthenticate() {
        return true;
    }
}
